#!/usr/bin/env python3

import socket
import sys
import subprocess
import os

def connect_to_server(svr_id):
	server_address = "/tmp/raft_cli_%d.sock" % svr_id
	socket_family = socket.AF_UNIX
	socket_type = socket.SOCK_STREAM

	sock = socket.socket(socket_family, socket_type)
	sock.connect(server_address)
	return sock

def exec_cmd(cmd):
	print("cmd = %s" % cmd)
	proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
	proc.wait(timeout=10)
	print(proc.stdout.read().decode('utf-8'))

def init_dir():
	exec_cmd(['rm', '-rf', '/tmp/raft'])
	exec_cmd(['mkdir', '/tmp/raft'])
	return

def conn_to_raft(svr_id):
	try:
		sock = connect_to_server(svr_id)
	except:
		print('connect to server failed')
		return
	print("Type 'exit' or 'quit' to quit ")
	while True:
		print("raft-%d> " % svr_id, end='')
		#print('send: [%s]' % cmd)
		raw = input()
		cmd = raw.strip()
		if cmd == '':
			continue
		if cmd=='q' or cmd == "exit" or cmd=="quit":
			break
		sock.sendall(cmd.encode())
		while True:
			rsp_buf = sock.recv(1024)
			rsp_str = rsp_buf.decode()
			print(rsp_str, end='')
			if rsp_str.find("command finished") >= 0:
				break
	sock.close()
	return

def fork_svr(svr_id):
	pid = os.fork()
	if pid == 0:
		d = '/tmp/raft/%d' % svr_id
		if not os.path.exists(d):
			os.mkdir(d)
		sid = '%d' % svr_id
		os.execl('./server', 'server', d, sid)
		print('os.execl failed')
		os.exit(0)
	return pid

def cmd_help():
	print('quit -- quit cli.py')
	print('help -- show this messages')
	print('init -- initiate raft directory')
	print('fork -- fork a new raft process')
	print('kill -- kill a raft process')
	print('conn -- connect to a raft process')
	print('list -- list all raft process')

def kill(pid):
    os.kill(pid, 9)
    while True:
        e_pid, status = os.wait()
        print('pid = %d, status = %d' % (e_pid, status))
        if e_pid == pid:
            break
    return

def main():
	svr_list = {}
	if not os.path.exists('server'):
		print('server does not exist')
		sys.exit(1)

	while True:
		print("cmd> ", end='')
		raw = input()
		cmd = raw.strip()
		if cmd == '':
			continue
		if cmd=='q' or cmd == "exit" or cmd=="quit":
			break
		fds = cmd.split()
		if fds[0]=='init':
			init_dir()
		elif fds[0]=='help':
			cmd_help()
		elif fds[0]=='fork':
			if not os.path.exists('/tmp/raft'):
				print('directory /tmp/raft does not exist')
				continue
			if len(fds) != 2:
				print('Usage: fork <id>')
				continue
			svr_id = int(fds[1])
			if svr_id<0 or svr_id>1000:
				print('svr_id must be between [0, 1000]')
				continue
			if svr_id in svr_list:
				print('svr_id(%d) alread existed' % svr_id)
				continue
			pid = fork_svr(svr_id)
			if pid > 0:
				print('svr_id %d, pid = %d' % (svr_id, pid))
				svr_list[svr_id] = pid
			else:
				print('fork failed')
		elif fds[0]=='kill':
			if len(fds) != 2:
				print('Usage: kill <id>')
				continue
			svr_id = int(fds[1])
			if svr_id not in svr_list:
				print('svr_id(%d) does not exist' % svr_id)
				continue
			pid = svr_list[svr_id]
			kill(pid)
			del svr_list[svr_id]
		elif fds[0]=='list':
			for svr_id in svr_list:
				pid = svr_list[svr_id]
				print('svr_id %d, pid = %d' % (svr_id, pid))
		elif fds[0]=='conn':
			if len(fds) != 2:
				print('Usage: conn <id>')
				continue
			svr_id = int(fds[1])
			if svr_id not in svr_list:
				print('svr_id(%d) is not existed' % svr_id)
				continue
			conn_to_raft(svr_id)
		else:
			pass

	for svr_id in svr_list:
		pid = svr_list[svr_id]
		kill(pid)
	return

if __name__=="__main__":
	main()

